package com.qjc.demo.thread.CyclicBarrier;

import java.util.Date;
import java.util.Random;
import java.util.concurrent.*;

/**
 * @Description: 回环屏障
 * @Author: qjc
 * @Date: 2020/7/27
 */
public class CyclicBarrierTest1 {

    /**
     * CountDownLatch计数器是一次性的，也就是等计数器值变为0后，再调用await方法和countdown方法都会立刻返回，这就起不到线程同步的效果了。
     * 为了满足计数器可以重置的需求,JDK提供了回环屏障CyclicBarrier，他可以让一组线程全部达到一个状态后再全部同时执行。
     * 这里之所以叫回环是因为当所有等待线程执行完毕，并重置CyclicBarrier的状态后他可以被重用。之所以叫做屏障是因为线程调用await方法后就会被阻塞，
     * 这个阻塞点就成为屏障点，等所有线程都调用了await方法后，线程们就会冲破屏障，继续向下运行。
     */

    /**
     * 说明了多个线程之间是相互等待的，假如计数器值为N，那么随后调用 await 方法的N-1个线程都会因为到达 障点而被阻塞，当第N个线程调用 await 后，计
     * 数器值为0了，这时候第N个线程才会发出通知唤醒前面的N-1个线程。也就是当全部线程都到达屏障点时才能一块继续向下执行。对于这个例子来说，使用 CountDownLatch
     * 也可以得到类似的输出结果 下
     */


    private final static int RUNNER_COUNT = 2;// 运动员数量（线程数）

    /**
     * 只要有 RUNNER_COUNT 个人准备好就可以进行比赛了
     * 第二个参数是个任务，这个任务的执行时机是当所有线程都到达屏障点后。
     */
    private static CyclicBarrier cyclicBarrier = new CyclicBarrier(RUNNER_COUNT, () -> System.out.println(Thread.currentThread() + " 裁判吹哨"));


    public static void main(String[] args) {
        System.out.println(new Date() + "  开始准备");
        //RUNNER_COUNT 个人比赛跑步
        ExecutorService executorService = Executors.newFixedThreadPool(RUNNER_COUNT);
//        ExecutorService executorService = new ThreadPoolExecutor(RUNNER_COUNT, RUNNER_COUNT, 0L,
//                TimeUnit.MILLISECONDS, new LinkedBlockingDeque<>(10), new ThreadPoolExecutor.AbortPolicy());

        executorService.submit(new Runner(cyclicBarrier, "张三"));
        executorService.submit(new Runner(cyclicBarrier, "李四"));
        executorService.submit(new Runner(cyclicBarrier, "王五"));
        executorService.submit(new Runner(cyclicBarrier, "赵六"));
        executorService.shutdown();
    }

}

class Runner implements Runnable {

    private CyclicBarrier cyclicBarrier;
    private String name;

    public Runner(CyclicBarrier cyclicBarrier, String name) {
        this.cyclicBarrier = cyclicBarrier;
        this.name = name;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(new Random().nextInt(5000));
            System.out.println(new Date() + "  " + name + "  准备好了");
            cyclicBarrier.await();
            System.out.println(new Date() + "  " + name + "  开始跑");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
